home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Graphics / NXPlot3d / Source / Expression.h.old < prev    next >
Text File  |  1990-10-14  |  10KB  |  255 lines

  1.  
  2. #import <objc/Object.h>
  3. #import <objc/HashTable.h>
  4. #import <appkit/errors.h>
  5.  
  6. /* function supplied by term implementor for evaluation */
  7. typedef float EXPTermEvalFunc(int numArgs, float *args);
  8.  
  9. /* enumeration state used to loop through all the variable names */
  10. typedef void *EXPEnumState;
  11.  
  12. /* private type for representing terms */
  13. typedef struct _EXPTerm *EXPTermPtr;
  14.  
  15. @interface Expression : Object
  16. {
  17.     char *text;            /* text of the expression */
  18.     NXHashTable *varTerms;    /* terms of variables */
  19.     EXPTermPtr parseTree;    /* terms from the parse */
  20.     NXHashTable *validFuncs;    /* functions we know how to evaluate */
  21.     int resolution;        /* number of points to calc for range vars */
  22.     BOOL resultsValid;        /* are the results up to date? */
  23.     float *results;        /* results of evaluation */
  24.     float resultsMin;        /* min of all results */
  25.     float resultsMax;        /* max of all results */
  26. }
  27.  /*
  28.   * An Expression object parses and evaluates the text of a mathematical
  29.   * expression.  The expression text may contain numbers, variables,
  30.   * arithmetic operations and program defined functions.  For example,
  31.   * an Expression object can parse the string "a+b*c", and if told
  32.   * values for a, b and c, can calculate the value of the expression.
  33.   *
  34.   * This ability to parse and evaluate expressions at runtime makes it
  35.   * easy for simple mathmatical programs to move beyond having canned example
  36.   * functions compiled into their executables, and instead allow the user
  37.   * to enter novel equations.  New formulas can be tried without recompiling
  38.   * the application.
  39.   * 
  40.   * Typically an Expression is created and then told to parse some text
  41.   * entered by the user.  The result of the parse is a parse tree, which is
  42.   * then used by the Expression to evaluate the expression, given a set
  43.   * of values for the expression's variables.  Variables can have either a
  44.   * single value, or can be made to take on a series of values ("vector
  45.   * variables").  For example, if you were graphing "A*x^2", you might
  46.   * make A have a single value, but let x run over a range of
  47.   * values that you would like to plot.
  48.   *
  49.   * The values of these vector variables can be set in two ways.  In the
  50.   * first way, a list of values is passed in using the setVar:vector:numVals: 
  51.   * method.  In the second way, the variable is given a range for its
  52.   * values with the setVar:min:max: method.  The actual values are then
  53.   * interpolated within that range.  The resolution of the expression
  54.   * determines how many values are calculated.  If you mix these two styles
  55.   * of vector variables, you must ensure that the number of explicitly
  56.   * set values assigned to any variables matches the resolution of the
  57.   * Expression.
  58.   *
  59.   * Expressions always operate lazily, meaning that results are never
  60.   * calculated until they are needed (usually when result values are asked
  61.   * for). This means just changing the values of variables is inexpensive.
  62.   *
  63.   * Expressions have methods which allow an application to enumerate the
  64.   * names of all the variables found by the parse.  This can be used to verify
  65.   * that the expression is valid, beyond whether it was parsable.  For
  66.   * example, in a certain context there may be a fixed set of variable names
  67.   * that may be used.  After a successful parse, the application can run
  68.   * through the names of all variables found, and ensure that they are all
  69.   * appropriate.
  70.   *
  71.   * Expressions understand the arithmetic operators +, -, *, /.  % is used
  72.   * for modulus (as in C) and ^ means is used to raise a quantity to a power.
  73.   * Parentheses can be used for grouping.
  74.   *
  75.   * Expressions have certain "built in" functions (e.g., sin()) that are
  76.   * understood.  It is also possible for applications to extend this default
  77.   * set of functions.  New functions are registered with the name of the
  78.   * function, the allowable number of arguments (can be variable), and a C
  79.   * procedure to call to perform the evaluation.  The built in functions are:
  80.   *
  81.   *    sin(x), cos(x), tan(x)        - elementary trig
  82.   *    asin(x), acos(x), atan(x)     - inverse elementary trig
  83.   *    exp(x), ln(x)            - exponential and natural log
  84.   *    sqrt(x)                - square root
  85.   *
  86.   * The constants "pi" and "e" are also built in.
  87.   */
  88.  
  89. - init;
  90.  /*
  91.   * Initialize an Expression that was just created via "allocFromZone:".  You
  92.   * cannot use a "+new" method to create Expression objects.  Below are some
  93.   * examples of creating Expressions.  The first expression goes in the 
  94.   * default malloc zone, the second is allocated in the same zone as
  95.   * otherObject.
  96.   *
  97.   *    id myExp1, myExp2;
  98.   *    myExp1 = [[Expression alloc] init];
  99.   *    myExp2 = [[Expression allocFromZone:[otherObject zone]] init];
  100.   *
  101.   */
  102.  
  103. - free;
  104.  /*
  105.   * Frees the Expression, including any array of results returned by
  106.   * the resultsVector:numVals: method.
  107.   */
  108.  
  109. - (BOOL)parse:(const char *)expressionString;
  110.  /*
  111.   * Parses the text of an expression.  A parse tree of terms is built up as
  112.   * a result of parsing expressionString.  The method returns whether the
  113.   * string was a legal expression.  expressionString is copied and retained
  114.   * within the Expression.
  115.   */
  116.  
  117. - (const char *)text;
  118.  /*
  119.   * Returns the last text parsed by the Expression.
  120.   */
  121.  
  122. - setResolution:(int)count;
  123.  /*
  124.   * Sets the resolution at which variables with a min and max range will
  125.   * be subdivided.  All vectors in the Expression must have the same
  126.   * number of values, which must be equal to the resolution of the
  127.   * Expression, at the time the Expression is evaluated.  Note that setting
  128.   * the list of values of a vector variable also changes the Expression's
  129.   * resolution.
  130.   */
  131.  
  132. - (int)resolution;
  133.  /*
  134.   * Returns the resolution of the Expression.
  135.   */
  136.  
  137. - setVar:(const char *)varName value:(float)val;
  138.  /*
  139.   * Sets the value of the variable named varName to val.  The variable
  140.   * will have that value as a constant throughout subsequent evaluations.
  141.   */
  142.  
  143. - (float)varValue:(const char *)varName;
  144.  /*
  145.   * Returns the value of the variable varName.  If the variable is being
  146.   * used as a vector, then its first value is returned.
  147.   */
  148.  
  149. - setVar:(const char *)varName vector:(float *)vals numVals:(int)count;
  150.  /*
  151.   * Sets the values of the variable named varName to be the array
  152.   * vals.  Count is the number of values in the vector.  This method
  153.   * also sets the resolution of the Expression to be count.
  154.   * All vectors in the Expression must have the same number of values,
  155.   * which must be equal to the resolution of the Expression, at the
  156.   * time the Expression is evaluated.  The list of vals should be a block
  157.   * of floats returned from malloc.  It is NOT copied, but will be freed by
  158.   * the Expression as part of its own free method.
  159.   */
  160.  
  161. - varVector:(const char *)varName vector:(float **)vals numVals:(int *)count;
  162.  /*
  163.   * Returns the vector of values of the variable varName by setting
  164.   * vals to point to the vector.  Count is set to the number of values.
  165.   */
  166.  
  167. - setVar:(const char *)varName min:(float)minVal max:(float)maxVal;
  168.  /*
  169.   * Sets the range of the variable varName to run from minVal to maxVal.
  170.   * The variables values will be determined by interpolating points
  171.   * within this range.  The resolution of the Expression determines the
  172.   * number of points that are taken within the range.
  173.   */
  174.  
  175. - var:(const char *)varName min:(float *)minVal max:(float *)maxVal;
  176.  /*
  177.   * Returns the smallest and largest value of the variable varName by setting
  178.   * minVal and maxVal.
  179.   */
  180.  
  181. - (float)resultValue;
  182.  /*
  183.   * Returns the value of the Expression when evaluated with its current
  184.   * attributes.  If there are vector variables in the Expression, it
  185.   * returns the result using the first value of all vectors.
  186.   */
  187.  
  188. - resultsVector:(float **)vals numVals:(int *)count;
  189.  /*
  190.   * Returns the values of the Expression when evaluated with its current
  191.   * attributes, by setting vals to point to the vector of results.  count
  192.   * is set to the number of results.  If there are no vector variables
  193.   * in the Expression, a single result is returned.
  194.   */
  195.  
  196. - resultsMin:(float *)minVal max:(float *)maxVal;
  197.  /*
  198.   * Returns the smallest and largest value of the results by setting
  199.   * minVal and maxVal.
  200.   */
  201.  
  202. - (EXPEnumState)beginVariableEnumeration;
  203. - (const char *)nextVariable:(EXPEnumState)state;
  204. - (void)endVariableEnumeration:(EXPEnumState)state;
  205.  /*
  206.   * Used to walk through the names of all variables parsed.  Example:
  207.   *     EXPEnumState state = [myExp beginVariableEnumeration];
  208.   *    const char *varName;
  209.   *    while (varName = [myExp nextVariable:state])
  210.   *        printf("A variable named %s was parsed.\n", varName);
  211.   *    [myExp endVariableEnumeration:state];
  212.   */
  213.  
  214. - addFuncTerm:(const char *)name minArgs:(int)min maxArgs:(int)max
  215.                     evalFunc:(EXPTermEvalFunc *)func;
  216.  /*
  217.   * Adds a function to the set of functions this Expression can parse.
  218.   * Functions look like "name(arg1, arg2,...)" in the text that is
  219.   * parsed.  At evaluation time the C function func() will be called with
  220.   * the values of the arguments.  The arguments are passed in an array of
  221.   * floats(see the EXPTermEvalFunc typedef above).  Func must return the value
  222.   * of the function with those arguments. min and max determine how many
  223.   * arguments the function can accept.  For example, min=1, max=1 means
  224.   * the function takes one argument.  A max value of -1 means an unbounded
  225.   * number of arguments is allowed.
  226.   */
  227.  
  228. - removeFuncTerm:(const char *)name;
  229.  /*
  230.   * Removes a function from the set of functions this Expression can parse.
  231.   * Be careful not to send this to an Expression that has already parsed
  232.   * text which made use of this function, since a reference to this FuncTerm
  233.   * will be left dangling in the parse tree.
  234.   */
  235.  
  236. @end
  237.  
  238. /* Error codes we raise */
  239.  
  240. typedef enum {
  241.     expErrInvalidVarName = NX_APPBASE + 10000,
  242.       /* An argument was passed referring to a variable whose name did not exist in the expression parsed. */
  243.     expErrInvalidVarType,
  244.       /* A variable was used in a way inconsistent with its type. */
  245.     expErrMinMax,
  246.       /* A min parameter was not less that its accompanying max parameter. */
  247.     expErrNoText,
  248.       /* A method could not complete because no expression had been parsed. */
  249.     expErrResolutionMismatch,
  250.       /* The number of points in the vector terms and the resolution of the Expression are inconsistent. */
  251.     expFuncTypeInUse
  252.       /* A message was sent attempting to add a function which has already been declared. */
  253. } EXPError;
  254.  
  255.